package com.cal.utms.model.dealing;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import com.cal.utms.action.user_maintenance.LoginAction;
import com.cal.utms.dao.dealing.DealDao;
import com.cal.utms.dao.maintenance.DealTypeDao;
import com.cal.utms.dao.maintenance.IssuerDaoImpl;
import com.cal.utms.dao.maintenance.MasterDataDaoImpl;
import com.cal.utms.dao.maintenance.NewFundDao;
import com.cal.utms.dto.dealing.RepoDealDto;
import com.cal.utms.entity.Deal;
import com.cal.utms.entity.DealInstrumentMap;
import com.cal.utms.entity.Dealer;
import com.cal.utms.entity.DelevaryMethod;
import com.cal.utms.entity.Fund;
import com.cal.utms.entity.Issuer;
import com.cal.utms.entity.SettlementMethod;
import com.cal.utms.util.Sequence;
import com.cal.utms.valuation.RepoDealCalculator;

public class RepoDealModel {

	public Deal creatRepoDeal(RepoDealDto repoDealDto) {
		Deal deal = new Deal();
		deal.setCreatedDate(new Date());
		deal.setDealType(new DealTypeDao().getDealTypeByCode("REPO"));
		deal.setCreatedUser(LoginAction.getCurrentLogingUser().getUserName());
		deal.setStatus("Initial");

		Sequence seq = new Sequence();
		String dealCode = "RP" + seq.getNextValue("DealSequence");
		deal.setDealCode(dealCode);
		List<DealInstrumentMap> dimList = new ArrayList<DealInstrumentMap>();
		deal.setDealInstrumentMaps(dimList);
		return mapDtoToDeal(repoDealDto, deal);
	}

	public Deal updateRepoDeal(Deal deal, RepoDealDto repoDealDto) {
		deal.setModifiedDate(new Date());
		deal.setModifiedUser(LoginAction.getCurrentLogingUser().getUserName());
		return mapDtoToDeal(repoDealDto, deal);
	}

	private Deal mapDtoToDeal(RepoDealDto repoDealDto, Deal deal) {
		DateFormat df = new SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH);
		NumberFormat nf = NumberFormat.getInstance();
		Date date = null;
		Number number;

		if (repoDealDto.getFund() != 0) {
			NewFundDao nfd = new NewFundDao();
			Fund fund = nfd.getById(repoDealDto.getFund());
			if (fund != null) {
				deal.setFund(fund);
			} else {
				repoDealDto.setSuccess(false);
				repoDealDto.setStatus("Invalid Fund!");
				return deal;
			}
		} else {
			repoDealDto.setSuccess(false);
			repoDealDto.setStatus("Empty Fund!");
			return deal;
		}

		if (repoDealDto.getIssuer() != 0) {
			IssuerDaoImpl issuerDao = new IssuerDaoImpl();
			Issuer issuer = issuerDao.getById(repoDealDto.getIssuer());
			if (issuer != null) {
				deal.setIssuer(issuer);
			} else {
				repoDealDto.setSuccess(false);
				repoDealDto.setStatus("Invalid Issuer!");
				return deal;
			}
		} else {
			repoDealDto.setSuccess(false);
			repoDealDto.setStatus("Empty Issuer!");
			return deal;
		}

		MasterDataDaoImpl masterDataDaoImpl = new MasterDataDaoImpl();
		if (repoDealDto.getSettlementCode() != 0) {
			SettlementMethod method = masterDataDaoImpl.getSettlementById(repoDealDto.getSettlementCode());
			if (method != null)
				deal.setSettlementMethod(method);
			else {
				repoDealDto.setSuccess(false);
				repoDealDto.setStatus("Invalid Settlement Methode!");
				return deal;
			}
		}
		if (repoDealDto.getDelevarymethode() != 0) {
			DelevaryMethod delevaryMethod = masterDataDaoImpl.getDelevaryMethodById(repoDealDto.getDelevarymethode());
			if (delevaryMethod != null)
				deal.setDelevarymethode(delevaryMethod);
			else {
				repoDealDto.setSuccess(false);
				repoDealDto.setStatus("Invalid Delevary Methode!");
				return deal;
			}
		}

		if (repoDealDto.getDealerCode() != 0) {
			Dealer dealer = masterDataDaoImpl.getdealerByid(repoDealDto.getDealerCode());
			if (dealer != null)
				deal.setDealerCode(dealer);
			else {
				repoDealDto.setSuccess(false);
				repoDealDto.setStatus("Invalid Dealer!");
				return deal;
			}
		}

		if (repoDealDto.getValueDate() != null) {
			try {
				System.out.println("valDt:" + repoDealDto.getValueDate());
				date = df.parse(repoDealDto.getValueDate());
				System.out.println(date);
				deal.setValueDate(date);
			} catch (ParseException pe) {
				repoDealDto.setSuccess(false);
				repoDealDto.setStatus("Value Date Parse Error!");
				return deal;
			}
		} else {
			repoDealDto.setSuccess(false);
			repoDealDto.setStatus("Empty Value Date!");
			return deal;
		}

		if (repoDealDto.getMaturityDate() != null) {
			try {
				System.out.println("matDt:" + repoDealDto.getMaturityDate());
				date = df.parse(repoDealDto.getMaturityDate());
				System.out.println(date);
				deal.setMaturityDate(date);
			} catch (ParseException pe) {
				repoDealDto.setSuccess(false);
				repoDealDto.setStatus("Maturity Date Parse Error!");
				return deal;
			}
		} else {
			repoDealDto.setSuccess(false);
			repoDealDto.setStatus("Empty Value Date!");
			return deal;
		}

		if (repoDealDto.getPrincipleValue() != null) {
			try {
				number = nf.parse(repoDealDto.getPrincipleValue());
				deal.setDealValue(new BigDecimal(number.doubleValue()));
			} catch (ParseException e) {
				repoDealDto.setSuccess(false);
				repoDealDto.setStatus("Principle Value Parse Error!");
				return deal;
			}
		} else {
			repoDealDto.setSuccess(false);
			repoDealDto.setStatus("Empty Principle Value!");
			return deal;
		}

		if (repoDealDto.getMaturityValue() != null) {
			try {
				number = nf.parse(repoDealDto.getMaturityValue());
				deal.setMaturityValue(new BigDecimal(number.doubleValue()));
			} catch (ParseException e) {
				repoDealDto.setSuccess(false);
				repoDealDto.setStatus("Maturity Value Parse Error!");
				return deal;
			}
		} else {
			repoDealDto.setSuccess(false);
			repoDealDto.setStatus("Empty Maturity Value!");
			return deal;
		}

		deal.setActualRate(new BigDecimal(repoDealDto.getActualRate().replace("%", "")));
		deal.setDayBasis(repoDealDto.getDayBasis());

		if (repoDealDto.getWithholdingTax() == 1) {
			deal.setWithholdingTax("Maturity");
			deal.setWithholdingTaxRate(new BigDecimal(repoDealDto.getWithholdingTaxRate().replace("%", "")));
			deal.setWithholdingCertificate("NotReceived");
		} else {
			deal.setWithholdingTax("No");
			deal.setWithholdingCertificate("No");
		}

		return deal;
	}

	public RepoDealDto mapRepoToDto(Deal deal) {
		NumberFormat nf = new DecimalFormat("###,###.00");
		DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
		RepoDealDto repoDealDto = new RepoDealDto();

		repoDealDto.setId(deal.getId());
		repoDealDto.setDealCode(deal.getDealCode());
		repoDealDto.setFund(deal.getFund().getId());
		repoDealDto.setIssuer(deal.getIssuer().getId());
		repoDealDto.setValueDate(df.format(deal.getValueDate()));
		repoDealDto.setMaturityDate(df.format(deal.getMaturityDate()));
		repoDealDto.setPrincipleValue(nf.format(deal.getDealValue().doubleValue()));
		repoDealDto.setActualRate(nf.format(deal.getActualRate().doubleValue()) + "%");
		repoDealDto.setDayBasis(deal.getDayBasis());
		if (deal.getWithholdingTax() != null) {
			if (deal.getWithholdingTax().equals("No")) {
				repoDealDto.setWithholdingTax((byte) 0);
			} else {
				repoDealDto.setWithholdingTax((byte) 1);
				if (deal.getWithholdingTaxRate() != null) {
					repoDealDto.setWithholdingTaxRate(nf.format(deal.getWithholdingTaxRate().doubleValue()) + "%");
				}
			}
		}
		if (deal.getSettlementMethod() != null) {
			repoDealDto.setSettlementCode(deal.getSettlementMethod().getId());
		}
		if (deal.getDelevarymethode() != null) {
			repoDealDto.setDelevarymethode(deal.getDelevarymethode().getId());
		}
		if (deal.getDealerCode() != null) {
			repoDealDto.setDealerCode(deal.getDealerCode().getId());
		}
		repoDealDto.setStatus(deal.getStatus());
		return repoDealDto;
	}

	public Deal confRepoDeal(RepoDealDto repoDealDto) {
		DealDao dealDao = new DealDao();
		Deal deal = dealDao.getByCode(repoDealDto.getDealCode());
		deal.setStatus("Confirmed");
		deal.setConfirmedUser(LoginAction.getCurrentLogingUser().getUserName());
		deal.setConfirmedDate(new Date());
		return mapDtoToDeal(repoDealDto, deal);
	}

	public RepoDealDto valuate(RepoDealDto repoDealDto) {
		DateFormat df = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH);
		NumberFormat nf = NumberFormat.getInstance();
		Date valueDate = null;
		Date maturityDate = null;
		Number principleValue = null;
		String withholdingTaxType = null;

		if (repoDealDto.getValueDate() == null) {
			repoDealDto.setStatus("Empty Value Date");
			repoDealDto.setSuccess(true);
			return repoDealDto;
		} else {
			try {
				System.out.println("valDt:" + repoDealDto.getValueDate());
				valueDate = df.parse(repoDealDto.getValueDate());
				System.out.println(valueDate);
			} catch (ParseException pe) {
				repoDealDto.setSuccess(false);
				repoDealDto.setStatus("Value Date Parse Error!");
				return repoDealDto;
			}
		}
		if (repoDealDto.getMaturityDate() == null) {
			repoDealDto.setStatus("Empty Maturity Date");
			repoDealDto.setSuccess(true);
			return repoDealDto;
		} else {
			try {
				System.out.println("matDt:" + repoDealDto.getMaturityDate());
				maturityDate = df.parse(repoDealDto.getMaturityDate());
				System.out.println(maturityDate);
			} catch (ParseException pe) {
				repoDealDto.setSuccess(false);
				repoDealDto.setStatus("Maturity Date Parse Error!");
				return repoDealDto;
			}
		}
		if (repoDealDto.getWithholdingTax() == 1) {
			if (Double.parseDouble(repoDealDto.getWithholdingTaxRate().replace("%", "")) < 0) {
				repoDealDto.setSuccess(false);
				repoDealDto.setStatus("Invalid Withholding Tax Rate");
				return repoDealDto;
			}
			withholdingTaxType = "Maturity";
		} else {
			withholdingTaxType = "No";
		}

		if (repoDealDto.getPrincipleValue() == null) {
			repoDealDto.setSuccess(false);
			repoDealDto.setStatus("Empty Principle Value!");
			return repoDealDto;
		} else {
			try {
				principleValue = nf.parse(repoDealDto.getPrincipleValue());
			} catch (ParseException e) {
				repoDealDto.setSuccess(false);
				repoDealDto.setStatus("Principle Value Parse Error!");
				return repoDealDto;
			}
		}

		RepoDealCalculator repoDealCalculator = new RepoDealCalculator();
		repoDealCalculator.valuateAllParameters(principleValue.doubleValue(), Double.parseDouble(repoDealDto.getActualRate().replace("%", "")), repoDealDto.getDayBasis(),
				valueDate, maturityDate, withholdingTaxType, Double.parseDouble(repoDealDto.getWithholdingTaxRate().replace("%", "")));
		repoDealDto.setMaturityValue(nf.format(repoDealCalculator.getMaturityValue()));
		repoDealDto.setWithholdingTaxValue(nf.format(repoDealCalculator.getWithholdingTax()));
		repoDealDto.setRate(nf.format(repoDealCalculator.getEffectiveRate()));
		return repoDealDto;
	}

}
